import 'package:flutter_clx_base/flutter_clx_base.dart';
import 'package:flutter_clx_base/widget/state_layout.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';

export 'package:easy_refresh/easy_refresh.dart';

class BaseListWidget extends StatefulWidget {
  final RequestDataCallback requestData;
  final int pageSize;
  final ItemBuilder itemBuilder;
  final Header? header;
  final Footer? footer;
  final Widget? startLoadWidget;
  final Widget? emptyWidget;
  final bool canLoadMore;
  final BaseListController? controller;
  final bool refreshOnStart; // 首次展示列表是否刷新数据

  const BaseListWidget({
    Key? key,
    required this.requestData,
    required this.itemBuilder,
    this.pageSize = 10,
    this.header,
    this.footer,
    this.startLoadWidget,
    this.controller,
    this.emptyWidget,
    this.canLoadMore = true, // 是否支持上拉刷新
    this.refreshOnStart = true,
  }) : super(key: key);

  @override
  State<BaseListWidget> createState() => _BaseListWidgetState();
}

class _BaseListWidgetState extends State<BaseListWidget> {
  late BaseListController _controller;
  final _CIProperties _headerProperties = _CIProperties(
    name: 'Header',
    alignment: MainAxisAlignment.center,
    infinite: false,
  );
  final _CIProperties _footerProperties = _CIProperties(
    name: 'Footer',
    alignment: MainAxisAlignment.start,
    infinite: true,
  );

  final List<dynamic> _dataList = [];
  int _page = 1;
  int _count = 0;
  bool _startLoadingFinish = false; // 首次进入loading加载完成标识
  StateType _stateType = StateType.loading; // 列表状态
  // 禁止手动触发滚动，处理刷新过程中禁止滚动列表操作
  bool _disallowScroll = false;
  // 禁止手动触发滚动遮罩State，单独刷新，否则列表项会刷新两次
  StateSetter? _disallowScrollState;
  bool _callReloading = false; // 触发自动刷新标识

  @override
  void initState() {
    super.initState();
    _controller = widget.controller ?? BaseListController();
    _controller._bind(this); // 绑定 BaseListWidget state
  }

  @override
  Widget build(BuildContext context) {
    final header = buildHeader();
    final footer = buildFooter();
    return Stack(
      children: [
        EasyRefresh(
          controller: _controller.c,
          refreshOnStart: widget.refreshOnStart,
          header: header,
          footer: footer,
          refreshOnStartHeader: BuilderHeader(
            triggerOffset: 70,
            clamping: true,
            position: IndicatorPosition.above,
            processedDuration: Duration.zero,
            builder: (ctx, state) {
              if (state.mode == IndicatorMode.inactive ||
                  state.mode == IndicatorMode.done) {
                _startLoadingFinish = true;
                return const SizedBox();
              }
              return Container(
                  padding: const EdgeInsets.only(bottom: 100),
                  width: double.infinity,
                  height: state.viewportDimension,
                  alignment: Alignment.center,
                  child: widget.startLoadWidget ??
                      SpinKitFadingCircle(
                        color: Theme.of(context).primaryColor,
                        size: 30,
                      ));
            },
          ),
          onRefresh: _onRefresh,
          onLoad: widget.canLoadMore ? _onLoad : null,
          child: buildScrollView(),
        ),
        // 列表刷新时，增加透明遮罩，禁止滚动列表
        StatefulBuilder(builder: (context, setState) {
          _disallowScrollState = setState;
          return Visibility(
            visible: _disallowScroll,
            child: Container(
              color: Colors.transparent,
              width: double.infinity,
              height: double.infinity,
            ),
          );
        }),
      ],
    );
  }

  Widget buildScrollView() {
    return CustomScrollView(slivers: buildSlivers());
  }

  Future<void> _onRefresh() async {
    _disallowScroll = false; // 开始刷新-重置标志位
    _callReloading = false; // 重置自动刷新标识
    _stateType = StateType.loading;
    _page = 1;
    await widget.requestData(
        _page, widget.pageSize, _requestSuccess, _requestError);
  }

  Future<void> _onLoad() async {
    _stateType = StateType.loading;
    _page++;
    await widget.requestData(
        _page, widget.pageSize, _requestSuccess, _requestError);
  }

  void _requestSuccess(List? result) {
    if (!mounted) {
      return;
    }
    result ??= [];
    if (_page == 1) {
      _dataList.clear();
      _controller.finishRefresh();
    }
    _dataList.addAll(result);
    _count = _dataList.length;
    setState(() {});
    _controller.finishLoad(result.length < widget.pageSize
        ? IndicatorResult.noMore
        : IndicatorResult.success);
    _stateType = isEmpty ? StateType.empty : StateType.success;
  }

  void _requestError(code, msg) {
    if (!mounted) {
      return;
    }
    _stateType = StateType.error;
    ToastUtil.showToast(msg);
    if (_page == 1) {
      _dataList.clear();
      _count = _dataList.length;
      _controller.finishRefresh();
    } else {
      _controller.finishLoad();
    }
    setState(() {});
  }

  /// Build header.
  Header buildHeader() =>
      widget.header ??
      ClassicHeader(
        clamping: _headerProperties.clamping,
        backgroundColor: _headerProperties.background
            ? Theme.of(context).colorScheme.surfaceVariant
            : null,
        mainAxisAlignment: _headerProperties.alignment,
        showMessage: _headerProperties.message,
        showText: _headerProperties.text,
        infiniteOffset: _headerProperties.infinite ? 70 : null,
        triggerWhenReach: _headerProperties.immediately,
        dragText: 'Pull to refresh'.tr,
        armedText: 'Release ready'.tr,
        readyText: 'Refreshing...'.tr,
        processingText: 'Refreshing...'.tr,
        processedText: 'Succeeded'.tr,
        noMoreText: 'No more'.tr,
        failedText: 'Failed'.tr,
        messageText: 'Last updated at %T'.tr,
      );

  /// Build footer.
  Footer buildFooter() =>
      widget.footer ??
      ClassicFooter(
        clamping: _footerProperties.clamping,
        backgroundColor: _footerProperties.background
            ? Theme.of(context).colorScheme.surfaceVariant
            : null,
        mainAxisAlignment: _footerProperties.alignment,
        showMessage: _footerProperties.message,
        showText: _footerProperties.text,
        infiniteOffset: _footerProperties.infinite ? 70 : null,
        triggerWhenReach: _footerProperties.immediately,
        noMoreIcon: const SizedBox(),
        dragText: 'Pull to load'.tr,
        armedText: 'Release ready'.tr,
        readyText: 'Loading...'.tr,
        processingText: 'Loading...'.tr,
        processedText: 'Succeeded'.tr,
        noMoreText: 'No more'.tr,
        failedText: 'Failed'.tr,
        messageText: 'Last updated at %T'.tr,
      );

  /// Check if there is no data.
  bool get isEmpty => _count == 0;

  dynamic getItem(int index) {
    return _dataList[index];
  }

  List<Widget> buildSlivers() {
    final header = buildHeader();
    final footer = buildFooter();
    return [
      if (header.position == IndicatorPosition.locator)
        const HeaderLocator.sliver(),
      if (isEmpty && _startLoadingFinish)
        SliverFillViewport(
          delegate: SliverChildBuilderDelegate(
            (context, index) {
              return widget.emptyWidget ??
                  StateLayout(
                    type: _stateType,
                    emptyImg: "default_drawing_1",
                    errorImg: "default_drawing_5",
                    onRefresh: _controller.reload,
                    loadingWidget: const SizedBox(),
                  );
            },
            childCount: 1,
          ),
        ),
      buildSliver(),
      if (footer.position == IndicatorPosition.locator)
        const FooterLocator.sliver(),
    ];
  }

  /// Build sliver.
  Widget buildSliver() {
    return SliverList(
      delegate: SliverChildBuilderDelegate(
        (context, index) {
          return buildItem(context, index, getItem(index));
        },
        childCount: _count,
      ),
    );
  }

  /// Build item widget.
  Widget buildItem(BuildContext context, int index, dynamic item) {
    return widget.itemBuilder(context, index, item);
  }

  // 刷新单个数据
  void notifySingleItem(index, item) {
    _dataList[index] = item;
    if (mounted) {
      setState(() {});
    }
  }

  // 禁止手动触发滚动
  void setDisallowScroll() {
    if (mounted) {
      _disallowScrollState?.call(() {
        _disallowScroll = true;
      });
    }
  }

  // 触发自动刷新列表
  void onCallReload() {
    _callReloading = true;
  }

  // 自动刷新标识
  bool get reloadFlag => _callReloading;
}

// 列表控制器
class BaseListController {
  late EasyRefreshController _controller;
  _BaseListWidgetState? _listState; // listState

  /// Binding with BaseListWidget state
  void _bind(_BaseListWidgetState state) {
    _listState = state;
  }

  BaseListController() {
    _controller = EasyRefreshController(
      controlFinishRefresh: true,
      controlFinishLoad: true,
    );
  }

  void finishRefresh() {
    _controller.finishRefresh();
  }

  void finishLoad([IndicatorResult result = IndicatorResult.success]) {
    _controller.finishLoad(result);
  }

  void resetFooter() {
    _controller.resetFooter();
  }

  // 重新加载数据
  void reload() {
    // 多次触发自动刷新无反应问题
    if (_listState?.reloadFlag == true) {
      return;
    }
    _listState?.onCallReload(); // 设置自动刷新标识
    _listState?.setDisallowScroll(); // 禁止手动触发滚动
    // force true 强制刷新，解决快速刷新只触发一次问题
    _controller.callRefresh(force: true);
  }

  // 刷新单个数据
  void notifySingleItem(index, item) {
    _listState?.notifySingleItem(index, item);
  }

  // 滚动到某个item index 位置
  void scrollToIndex(
    int index,
    double height, {
    bool animated = true,
  }) {
    _controller.callRefresh(
      scrollController: ScrollController(
        initialScrollOffset: index * height,
      ),
    );
  }

  get c => _controller;
}

typedef SuccessCallback = Function(List? list);
typedef ErrorCallback = Function(dynamic code, String? msg);
typedef RequestDataCallback = Function(
    int page, int pageSize, SuccessCallback success, ErrorCallback error);
typedef ItemBuilder = Function(BuildContext context, int index, dynamic item);

class _CIProperties {
  final String name;
  bool disable = false;
  bool clamping = false;
  bool background = false;
  MainAxisAlignment alignment;
  bool message = true;
  bool text = true;
  bool infinite;
  bool immediately = false;

  _CIProperties({
    required this.name,
    required this.alignment,
    required this.infinite,
  });
}
